package org.zjt.chapter1.io;

import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http2.Http2ConnectionHandler;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

/**
 * Description:
 *
 *      1、handler 与 childHandler 区别:
 *
 *          handler 是channel 用来处理连接事件的，由 ServerChannel来处理。 BootEventLoop处理
 *
 *          childHandler 由接受到子channel 来处理。WorkEventLoop来处理。
 *
 *
 *      2、服务器端的 ServerChannel 和 childChannel 流程。
 *
 *          ServerBootStrap --bind--> ServerChannel   ---连接-->  eventLoop读写等事件  ---event-->  childChanel
 *
 *
 *
 * @author juntao.zhang
 * Date: 2018-07-12 下午7:42
 * @see
 */
@Slf4j
public class NioNetworkOperationalTest {

    @Test
    public void server()  {
        NioEventLoopGroup eventExecutors = new NioEventLoopGroup();
        try {
            ChannelFuture sync = new ServerBootstrap().group(eventExecutors)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY,true)
                    .handler(new ChannelInboundHandlerAdapter(){
                        @Override
                        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

                            // handler 接受channel连接事件，所以必须将事件fire出去，要不然会卡死到这里。
                            log.info("handler server msg:{}",msg);

                            ctx.fireChannelRead(msg);
                        }})
                    .childHandler(new ChannelInboundHandlerAdapter() {
                        @Override
                        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

                            // 都是 PooledUnsafeDirectByteBuf ，需要手动释放引用。

                            ByteBuf cast = ByteBuf.class.cast(msg);
                            byte[] bytes = new byte[cast.readableBytes()];
                            cast.readBytes(bytes);

                            log.info("childHandler server msg:{}",new String(bytes));
                            ReferenceCountUtil.release(msg);
                        }
                    }).bind(8900).addListener(future -> log.info("bind isSuccess:{}",future.isSuccess())).sync();

            sync.channel().closeFuture().addListener(future -> log.info("close isSuccess:{}",future.isSuccess())).sync();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            eventExecutors.shutdownGracefully();
        }
    }



    @Test
    public void client()  {
        NioEventLoopGroup eventExecutors = new NioEventLoopGroup();
        try {
            Channel channel = new Bootstrap().group(eventExecutors).channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY,true)
                    .handler(new SimpleChannelInboundHandler<Object>() {
                        @Override
                        protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
                            log.info("client msg:{}", msg);
                        }

                        @Override
                        public void channelActive(ChannelHandlerContext ctx) throws Exception {
//                            ctx.writeAndFlush(Unpooled.wrappedBuffer("sssss".getBytes()));
                        }
                    }).connect("localhost", 8900).addListener(future -> log.info("connect isSuccess:{}", future.isSuccess())).sync().channel();


            log.info("sssssssssssss");
            for (int i = 0; i < 1000000; i++) {
                channel.write(Unpooled.wrappedBuffer((i +" sssss" ).getBytes()));
                channel.flush();
            }

            log.info("over");
            channel.closeFuture().sync();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            eventExecutors.shutdownGracefully();
        }

    }
}
